package com.zby.common.utils;

import com.zby.common.exception.BlogException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.UUID;

@Component
public class JwtUtils {
    /**
     * 毫秒数 - 1秒对应的毫秒值（单位：毫秒）
     */
    protected static final long MILLIS_SECOND = 1000L;

    /**
     * 毫秒数 - 1分钟对应的毫秒值（60秒）
     */
    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;

    // Getter和Setter方法
    /**
     * JWT加密密钥（通过配置中心可覆盖）
     * @apiNote 配置路径：token.secret
     * @default 默认值：123456abcdefghijklmnopqrstuvwxyz
     */
    @Setter
    @Getter
    @Value("${token.secret:123456abcdefghijklmnopqrstuvwxyz}")
    private String secret;
    /**
     * Token有效期配置（单位：分钟）
     * @apiNote 配置路径：token.expireTime
     * @default 默认有效期：30分钟
     */
    @Value("${token.expireTime:7}")
    private int expireTime;
    @Value("${token.refreshTime:10080}")
    private int refreshTime;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    private static final String KEY_ID = "login:user:Access:";
    private static final String LONG_KEY_ID = "login:user:Refresh:";

    // 默认构造函数
    public JwtUtils() {
    }

    // 带参数的构造函数，用于手动设置secret和expireTime
    public JwtUtils(String secret, int expireTime) {
        this.secret = secret;
        this.expireTime = expireTime;
    }

    /**
     * 创建令牌
     *
     * @param id ID
     * @return 令牌
     */
    public String createToken(String id) {
        // 确保secret不为null
        String secretKey = (secret != null) ? secret : "123456abcdefghijklmnopqrstuvwxyz";
        int expTime = (expireTime > 0) ? expireTime : 7;

        JwtBuilder builder = Jwts.builder().claim("key",
                UUID.randomUUID().toString()).claim("id", id)
                .signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
                .expiration(new Date(System.currentTimeMillis() + 10 * MILLIS_SECOND));
        // 创建令牌并返回
        String compact = builder.compact();
        // 将令牌存入redis中
        stringRedisTemplate.opsForValue().set(KEY_ID+id, compact);
        // 将令牌进行加密并返回
        return compact ;
    }

    /**
     * 从令牌中获取数据声明
     *
     * @param token 令牌
     * @return 数据声明
     */
    public Claims parseToken(String token) {
        try {
            // 检查token是否为空
            if (token == null || token.isEmpty()) {
                throw new IllegalArgumentException("Token is null or empty");
            }

            // 确保secret不为null
            String secretKey = (secret != null) ? secret : "123456abcdefghijklmnopqrstuvwxyz";

            Jws<Claims> claimsJws = Jwts.parser().verifyWith(Keys.hmacShaKeyFor(secretKey.getBytes())).build().parseSignedClaims(token);
            return claimsJws.getPayload();
        } catch (IllegalArgumentException e) {
            // 捕获token空异常
            throw new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "Token无效: " + e.getMessage());
        } catch (ExpiredJwtException e) {
            // 捕获token过期异常
            throw new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "Token已过期: " + e.getMessage());
        } catch (JwtException e) {
            // 捕获其他JWT异常
            throw new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "Token解析错误: " + e.getMessage());
        }
    }
    // 长期令牌
    public String createLongTermToken(String oldToken) {
        // 确保secret不为null
        String secretKey = (secret != null) ? secret : "123456abcdefghijklmnopqrstuvwxyz";
        int refreshExpTime = (refreshTime > 0) ? refreshTime : 10080;
        // 过期的令牌如何解析？
        Claims claims = expiredToken(oldToken);
        Object oldId = claims.get("id");
        String id = (String) oldId;
        if (id == null) {
            throw new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "Token未查询到,请登录");
        }
        try {
            String redisToken = stringRedisTemplate.opsForValue().get(KEY_ID + id);
            String redisLongToken = stringRedisTemplate.opsForValue().get(LONG_KEY_ID + id);
            if (redisToken.equals(oldToken)) {
                stringRedisTemplate.delete(KEY_ID + id);
                //创建令牌并返回
                JwtBuilder builder = getJwtBuilder(id, secretKey, refreshExpTime);
                // 创建令牌并返回
                String compact = builder.compact();
                stringRedisTemplate.opsForValue().set(LONG_KEY_ID + id, compact);

                return compact;
            } else if (redisLongToken.equals(oldToken)) {
                stringRedisTemplate.delete(LONG_KEY_ID + id);
                JwtBuilder builder = getJwtBuilder(id, secretKey, refreshExpTime);
                String compact = builder.compact();
                stringRedisTemplate.opsForValue().set(LONG_KEY_ID + id, compact);
                return compact;

            }

        } catch (Exception e) {
            throw new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "Token换取异常");

        }
        throw  new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "Token无效");
    }



    private static JwtBuilder getJwtBuilder(String id, String secretKey, int refreshExpTime) {
        //创建令牌并返回
        JwtBuilder builder = Jwts.builder().claim("key",
                        UUID.randomUUID().toString()).claim("id", id)
                .signWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
                .expiration(new Date(System.currentTimeMillis() + refreshExpTime * MILLIS_MINUTE));
        // 创建令牌并返回
        return builder;
    }
    // 过期token解析
    public Claims expiredToken(String token){
        try {
            // 检查token是否为空
            if (token == null || token.isEmpty()) {
                throw new IllegalArgumentException("Token is null or empty");
            }

            // 确保secret不为null
            String secretKey = (secret != null) ? secret : "123456abcdefghijklmnopqrstuvwxyz";

            // 允许解析过期的token
            return Jwts.parser()
                    .verifyWith(Keys.hmacShaKeyFor(secretKey.getBytes()))
                    .build()
                    .parseClaimsJwt(token)
                    .getPayload();
        } catch (ExpiredJwtException e) {
            // 如果是过期异常，则返回过期的 claims
            return e.getClaims();
        } catch (JwtException e) {
            // 捕获其他JWT异常
            throw new BlogException(ResultEnum.UNAUTHORIZED.getCode(), "oldToken解析错误: " + e.getMessage());
        }
    }



}